<script lang="tsx">
import { useDesign } from '@/hooks/useDesign';
import { propTypes } from '@/utils/propTypes';
import { getSlot } from '@/utils/tsxHelper';
import { ElCol, ElForm, ElFormItem, ElRow, type FormRules } from 'element-plus';
import { omit } from 'es-toolkit';
import { get, set } from 'es-toolkit/compat';
import { computed, defineComponent, onMounted, ref, unref, type PropType } from 'vue';
import { getPlaceholder, setComponentProps, setItemComponentSlots } from './helper';
import { componentMap } from './helper/componentMap';
import { ComponentNameEnum, type FormProps, type FormSchema } from './types';

const prefixCls = useDesign().getPrefixCls('form');

export default defineComponent({
  name: 'Form',
  props: {
    // 生成Form的布局结构数组
    schema: {
      type: Array as PropType<FormSchema[]>,
      default: () => []
    },
    rules: {
      type: Object as PropType<FormRules>,
      default: () => ({})
    },
    isCustom: propTypes.bool.def(false),
    /** 是否使用栅格化布局 */
    isCol: propTypes.bool.def(true),
    /** 是否自动设置表单项的 placeholder */
    autoSetPlaceholder: propTypes.bool.def(true),
    model: {
      type: Object as PropType<any>,
      default: () => ({})
    }
  },
  setup(props, { slots, expose, emit }) {
    const elFormRef = ref<ComponentRef<typeof ElForm>>();
    const formModel = ref<Recordable>(props.model);

    const mergeProps = ref<FormProps>({});

    const getProps = computed(() => {
      return { ...props, ...unref(mergeProps) };
    });
    const setProps = (props: FormProps) => {
      mergeProps.value = { ...unref(mergeProps), ...props };
    };

    onMounted(() => {
      emit('register', unref(elFormRef)?.$parent, unref(elFormRef));
    });

    const renderWrap = () => {
      const { isCol } = unref(getProps);
      const content = isCol ? <ElRow gutter={20}>{renderFormItemWrap()}</ElRow> : renderFormItemWrap();
      return content;
    };

    const renderFormItemWrap = () => {
      const { schema = [], isCol } = unref(getProps);
      return schema
        .filter((v) => !v.remove)
        .map((item) => {
          const isDivider = item.component === 'Divider';
          const Comp = componentMap[item.component as keyof typeof componentMap] as ReturnType<typeof defineComponent>;
          return isDivider ? (
            // 分隔线
            <Comp {...{ contentPosition: 'left', ...item.componentProps }}>{item.label}</Comp>
          ) : isCol ? (
            // 栅格布局
            <ElCol {...item.componentProps}>{renderFormItem(item)}</ElCol>
          ) : (
            // 普通表单项
            renderFormItem(item)
          );
        });
    };

    const renderFormItem = (item: FormSchema) => {
      // 默认行为项
      const formItemSlots: Recordable = {
        default: () => {
          if (item?.formItemProps?.slots?.default) {
            return item?.formItemProps?.slots?.default(formModel.value);
          } else {
            const Comp = componentMap[item.component as keyof typeof componentMap] as ReturnType<typeof defineComponent>;
            // 是否自动设置 placeholder
            const { autoSetPlaceholder } = unref(getProps);
            // 获取组件的插槽
            const componentSlots = (item?.componentProps as any)?.slots || {};
            const slotsMap: Recordable = {
              ...setItemComponentSlots(componentSlots)
            };

            // 如果是Select组件
            if (item.component === ComponentNameEnum.SELECT) {
            }

            if (item.component === ComponentNameEnum.SELECT_V2 && componentSlots.default) {
              slotsMap.default = ({ item }: { item: any }) => {
                return componentSlots.default(item);
              };
            }

            if ([ComponentNameEnum.RADIO_GROUP, ComponentNameEnum.RADIO_BUTTON].includes(item.component as ComponentNameEnum)) {
            }

            if ([ComponentNameEnum.CHECKBOX_GROUP, ComponentNameEnum.CHECKBOX_BUTTON].includes(item.component as ComponentNameEnum)) {
            }

            const renderComp = () => {
              const itemVal = computed({
                get: () => get(formModel.value, item.field),
                set: (val) => set(formModel.value, item.field, val)
              });

              const componentConfig = {
                ref: (el: any) => setComponentRefMap(el, item.field),
                ...(autoSetPlaceholder && getPlaceholder(item)),
                ...setComponentProps(item),
                style: item.componentProps?.style || { width: '100%' }
              };

              if (item.component === ComponentNameEnum.UPLOAD) {
                (componentConfig as any).fileList = itemVal.value;
              } else {
                (componentConfig as any).modelValue = itemVal.value;
                (componentConfig as any)['onUpdate:modelValue'] = (val: any) => {
                  itemVal.value = val;
                };
              }

              return <Comp {...componentConfig}>{{ ...slotsMap }}</Comp>;
            };

            return <>{renderComp()}</>;
          }
        }
      };

      // label 插槽
      if (item?.formItemProps?.slots?.label) {
        formItemSlots.label = (...args: any[]) => item?.formItemProps?.slots?.label?.(...args);
      }
      // error 插槽
      if (item?.formItemProps?.slots?.error) {
        formItemSlots.error = (...args: any[]) => item?.formItemProps?.slots?.error?.(...args);
      }
      return (
        <ElFormItem v-show={!item.hidden} ref={(el) => setFormItemRefMap(el, item.field)} {...(item?.formItemProps ?? {})} prop={item.field} label={item.label}>
          {formItemSlots}
        </ElFormItem>
      );
    };

    const formItemComponents = ref<{ [key: string]: any }>({});
    const setFormItemRefMap = (ref: any, field: string) => {
      formItemComponents.value[field] = ref;
    };
    const getFormItemExpose = (field: string) => {
      return unref(formItemComponents)[field];
    };

    const formComponents = ref<{ [key: string]: any }>({});
    const setComponentRefMap = (ref: any, field: string) => {
      formComponents.value[field] = ref;
    };
    const getComponentExpose = (field: string) => {
      return unref(formComponents)[field];
    };

    expose({ setProps, getFormItemExpose, getComponentExpose, formModel });

    return () => (
      <ElForm
        ref={elFormRef}
        class={prefixCls}
        // @ts-ignore
        onSubmit={(e: Event) => e.preventDefault()}
        model={unref(getProps).isCustom ? unref(getProps).model : formModel}
        {...omit(unref(getProps), ['schema', 'isCol', 'autoSetPlaceholder', 'isCustom', 'model'])}
      >
        {{
          default: () => {
            const { isCustom } = unref(getProps);
            return isCustom ? getSlot(slots, 'default') : renderWrap();
          }
        }}
      </ElForm>
    );
  }
});
</script>
<style lang="less" scoped>
.@{elNamespace}-form.@{adminNamespace}-form .@{elNamespace}-row {
  margin-right: 0 !important;
  margin-left: 0 !important;
}

.@{elNamespace}-form--inline {
  :deep(.el-form-item__content) {
    & > :first-child {
      min-width: 229.5px;
    }
  }
  .@{elNamespace}-input-number {
    // 229.5px是兼容el-input-number的最小宽度,
    min-width: 229.5px;
  }
}
</style>
